﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Mindfor
{
	/// <summary>
	/// Defines method to search for types.
	/// </summary>
	public static class TypeFinder
	{
		#region Get type

		/// <summary>
		/// Searches type by typeName in domain assemblies.
		/// </summary>
		/// <param name="domain">Application domain.</param>
		/// <param name="typeName">Full type name.</param>
		/// <param name="ignoreCase">True to ignore case. Otherwise False.</param>
		/// <returns>Type or Null if not found.</returns>
		public static Type GetTypeFromDomain(AppDomain domain, string typeName, bool ignoreCase)
		{
			Assembly[] asms = domain.GetAssemblies();

			foreach (Assembly asm in asms)
			{
				Type findType = asm.GetType(typeName, false, ignoreCase);
				if (findType != null)
					return findType;
			}
			return null;
		}

		/// <summary>
		/// Searches type by typeName in domain assemblies. Case is ignored.
		/// </summary>
		/// <param name="domain">Application domain.</param>
		/// <param name="typeName">Full type name.</param>
		/// <returns>Type or Null if not found.</returns>
		public static Type GetTypeFromDomain(AppDomain domain, string typeName)
		{
			return GetTypeFromDomain(domain, typeName, true);
		}

		/// <summary>
		/// Searches type by typeName in current domain assemblies. Case is ignored.
		/// </summary>
		/// <param name="typeName">Full type name.</param>
		/// <returns>Type or Null if not found.</returns>
		public static Type GetTypeFromCurrentDomain(string typeName)
		{
			return GetTypeFromCurrentDomain(typeName, true);
		}

		/// <summary>
		/// Searches type by typeName in current domain assemblies.
		/// </summary>
		/// <param name="typeName">Full type name.</param>
		/// <param name="ignoreCase">True to ignore case. Otherwise False.</param>
		/// <returns>Type or Null if not found.</returns>
		public static Type GetTypeFromCurrentDomain(string typeName, bool ignoreCase)
		{
			return GetTypeFromDomain(AppDomain.CurrentDomain, typeName, ignoreCase);
		}

		#endregion

		#region Get types

		/// <summary>
		/// Returns type of specified namespace in domain assemblies. 
		/// </summary>
		/// <param name="domain">Application domain.</param>
		/// <param name="namespace">Namespace to search.</param>
		/// <returns>Array of namespace types.</returns>
		public static Type[] GetTypesFromDomain(AppDomain domain, string @namespace)
		{
			List<Type> types = new List<Type>();
			Assembly[] asms = domain.GetAssemblies();
			string ns = @namespace.ToLower();

			foreach (Assembly asm in asms)
			{
				try
				{
					foreach (Type t in asm.GetTypes())
					{
						if (t.Namespace != null && t.Namespace.ToLower() == ns)
							types.Add(t);
					}
				}
				catch (ReflectionTypeLoadException)
				{
					// we can not load types from assembly => just skip
				}
			}
		

			return types.ToArray();
		}

		/// <summary>
		/// Returns type of specified namespace in current domain assemblies. 
		/// </summary>
		/// <param name="namespace">Namespace to search.</param>
		/// <returns>Array of namespace types.</returns>
		public static Type[] GetTypesFromCurrentDomain(string @namespace)
		{
			return GetTypesFromDomain(AppDomain.CurrentDomain, @namespace);
		}

		#endregion
	}
}
